﻿using System.Collections.Generic;
using System.Linq;
using CharacterCreation.Data.Annotations;
using CharacterCreation.Data.QueryBuilders;
using System;

namespace CharacterCreation.Data {
    public class MetaDataStore {
        public static List<TableDefinition> TableDefinitions { get; set; }
        
        public MetaDataStore() {
            if (TableDefinitions == null) TableDefinitions = new List<TableDefinition>();
        }

        public void AddTableDefinition<T>() {
            //Return if the model definition is already loaded and the model is up to date.
            if (TableDefinitions.Where(t => t.Model == typeof(T)).FirstOrDefault() != null &&
                TableDefinitions.Where(t => t.Model == typeof(T)).FirstOrDefault().IsUpToDate)
                return;

            TableAttribute tableAttribute = TableBuilder.GetTableAttribute<T>();
            string query =
                    string.Format(@"
                    select	c.name as 'column_name', 
		                    x.name as 'type_name', 
		                    x.max_length
                    from	sys.columns c 
                    join	sys.types x on c.system_type_id = x.user_type_id
                    where   c.object_id = object_id('{0}')", tableAttribute.TableName);

            var columnDefinitions = DataContext.ExecuteQuery<SqlColumnDefinition>(query);

            TableDefinition tableDefinition = new TableDefinition() {
                TableAttribute = tableAttribute,
                Model = typeof(T),
                Exists = DataContext.TableExists<T>(false)
            };

            var cAttrib = new List<ColumnAttribute>();
            var cDef = new List<ColumnDefinition>();

            foreach (var pInfo in typeof(T).GetProperties()
                    .Where(p => p.GetCustomAttributes(typeof(IgnoreAttribute), false).FirstOrDefault() == null)) {
                
                ColumnAttribute cAtt = TableBuilder.GetColumnAttribute<T>(pInfo);
                cAttrib.Add(cAtt);
            }

            foreach (var columnDefinition in columnDefinitions) {
                ColumnDefinition cd = new ColumnDefinition() {
                    ColumnName = columnDefinition.column_name,
                    TypeName = columnDefinition.type_name,
                    MaxLength = columnDefinition.max_length,
                    IsIdentityColumn = columnDefinition.column_name == "Id"
                };
                cDef.Add(cd);
            }

            tableDefinition.ColumnAttributes = cAttrib;
            tableDefinition.ColumnDefinitions = cDef;
            tableDefinition.IsUpToDate = cAttrib.Count == cDef.Count;

            if (!tableDefinition.IsUpToDate) {
                DataContext.DropTable<T>();
                DataContext.CreateTable<T>();
                AddTableDefinition<T>();
                return;
            }


            TableDefinitions.Add(tableDefinition);
        }

        public static string IdentityFieldName(Type targetType)
        {
            TableDefinition td = TableDefinitions.FirstOrDefault(t => t.Model == targetType);
            if (td != null)
            {
                return td.ColumnDefinitions.First(c => c.IsIdentityColumn).ColumnName;
            }
            else throw new Exception("No Identity column");
        }

    }

    internal class SqlColumnDefinition {
        public string column_name { get; set; }
        public string type_name { get; set; }
        public int max_length { get; set; }
    }
}
